#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <iostream>

using namespace std;

//输出重定向:将本来向标准输出写入的数据改为向其他文件写入
//int main()
//{
//    close(1);
//    int fd1 = open("./log1.txt", O_WRONLY | O_CREAT, 0664);
//    cout << "fd1:" << fd1 << endl;
//    printf("hello printf\n");
//    fprintf(stdout, "hello fprintf\n");
//
//    //下面我来解释一下上面情况发生的原理
//    //printf的本质是向stdout输出打印
//    //fprintf是向指定的FILE中写入数据
//    //而之前我们知道,stdout是一个FILE*
//    //这个FILE本质是一个结构体,里面包含了一个整数
//    //是对应系统层面的这个文件的fd
//    //那么stdout对应的这个FILE结构体,里面包含了fd,这个值为1
//    //所以stdout只会关心文件描述符为1的文件,那么这个文件是谁
//    //它不会关心
//    //所以原本向显示器打印的数据,被写入到了log.txt里面
//    
//    //具体的流程是这样的,首先这些库函数里面封装了系统调用的接口
//    //当你传入的stdout参数的时候,里面系统调用接口,实际就是使用的
//    //fd为1的文件描述符,原本的1是对应的显示器文件,向显示器上打印
//    //但是由于现在的1对应的是txt文件,所以把数据往txt文件里面写入了
//    return 0;
//}

//输入重定向:将本来向标准输入读取的数据改为读取其他文件的数据
//int main()
//{
//    close(0);
//    int fd1 = open("./log.txt", O_RDONLY);
//
//    char* buffer[1024];
//    ssize_t size1 = read(0, buffer, sizeof(buffer));
//    cout << "fd:" << fd1 << endl;
//    cout << "size1:" << size1 << endl;
//    printf("%s", buffer);
//    return 0;
//}

//追加重定向:和输出重定向类似,只是变为了追加
//int main()
//{
//    close(1);
//    int fd1 = open("./log.txt", O_CREAT | O_WRONLY | O_APPEND, 0664);
//    cout << "append success!!!" << endl;
//    cout << "fd1:" <<  fd1 << endl;
//
//    return 0;
//}

//上面说到FILE的结构体里面会有文件描述符
//我们来验证一下
int main()
{
    //_fileno就是FILE这个结构体里面对于文件描述符的封装
    cout << "stdin -> fd:" << stdin->_fileno << endl;
    cout << "stdout -> fd:" << stdout->_fileno << endl;
    cout << "stderr -> fd:" << stderr->_fileno << endl;

    //我们打开一个文件,看看它的文件描述符是不是3
    FILE* fp = fopen("./log.txt", "r");
    if (nullptr == fp)
    {
        perror("fopen error");
        return 1;
    }
    cout << "fp -> fd:" << fp->_fileno << endl;

    //当我们关闭了0,看看此时的一个新文件,它的文件描述符是不是0
    close(0);
    FILE* fp1 = fopen("./log1.txt", "w");
    cout << "fp1 -> fd:" << fp1->_fileno << endl;

    return 0;
}
